package com.zxy.zxyrpc.protocol;

import com.zxy.zxyrpc.exception.RpcException;
import com.zxy.zxyrpc.model.ErrorCode;
import com.zxy.zxyrpc.model.RpcRequest;
import com.zxy.zxyrpc.model.RpcResponse;
import com.zxy.zxyrpc.serializer.Serializer;
import com.zxy.zxyrpc.serializer.SerializerFactory;
import io.vertx.core.buffer.Buffer;

import java.io.IOException;

/**
 * 协议消息解码器
 *
 * @author zxy
 * @since 2025/5/22
 **/
public class ProtocolMessageDecoder {
    /**
     * 解码
     *
     * @param buffer 网络数据缓存
     */
    public static ProtocolMessage<?> decode(Buffer buffer) throws IOException {
        // 魔数效验
        byte magic = buffer.getByte(0);
        if (magic != ProtocolConstant.PROTOCOL_MAGIC)
            throw new RpcException(ErrorCode.PARAMS_ERROR, "消息 magic 非法");
        // 解析协议消息
        ProtocolMessage.Header header = new ProtocolMessage.Header();
        header.setMagic(magic);
        header.setVersion(buffer.getByte(1));
        header.setSerializer(buffer.getByte(2));
        header.setType(buffer.getByte(3));
        header.setStatus(buffer.getByte(4));
        header.setRequestId(buffer.getLong(5));
        header.setBodyLength(buffer.getInt(13));
        byte[] bodyBytes = buffer.getBytes(17, 17 + header.getBodyLength());
        // 指定序列化器
        ProtocolMessageSerializerEnum serializerEnum = ProtocolMessageSerializerEnum.getEnumByKey(header.getSerializer());
        if (serializerEnum == null)
            throw new RpcException(ErrorCode.NOT_FOUND_ERROR, "序列化协议不存在");
        Serializer serializer = SerializerFactory.getInstance(serializerEnum.getValue());
        // 识别消息类型，返回对应的信息对象
        ProtocolMessageTypeEnum messageTypeEnum = ProtocolMessageTypeEnum.getEnumByKey(header.getType());
        if (messageTypeEnum == null)
            throw new RpcException(ErrorCode.NOT_FOUND_ERROR, "序列化消息类型不存在");
        switch (messageTypeEnum) {
            case REQ:
                RpcRequest req = serializer.deserialize(bodyBytes, RpcRequest.class);
                return new ProtocolMessage<>(header, req);
            case RES:
                RpcResponse res = serializer.deserialize(bodyBytes, RpcResponse.class);
                return new ProtocolMessage<>(header, res);
            case HEART_BEAT:
            case OTHERS:
            default:
                throw new RpcException(ErrorCode.SYSTEM_ERROR, "暂不支持该类型消息");
        }
    }
}
